<template>
  <el-drawer v-model="drawerVisible" :title="`${parameter.userName}登录记录`" :size="drawerWidth" direction="rtl">
    <div class="drawer-body" ref="scrollEl" @scroll="onScroll">
      <template v-if="isFirstLoading">
        <el-skeleton :rows="4" animated />
        <el-skeleton :rows="4" animated class="mt12" />
      </template>

      <el-empty v-else-if="items.length === 0" description="暂无登录记录" />

      <el-timeline v-else>
        <el-timeline-item
          v-for="(row, idx) in items"
          :key="row.id || idx"
          :timestamp="formatTime(row.createTime)"
          :type="row.success ? 'success' : 'danger'"
        >
          <div class="item">
            <div class="item__header">
              <span class="item__user">{{ row.userName || row.account }}</span>
              <el-tag :type="row.success ? 'success' : 'danger'" size="small" effect="plain">
                {{ row.success ? "登录成功" : "登录失败" }}
              </el-tag>
            </div>
            <div class="item__meta">
              <span class="meta__cell">IP：{{ row.ip || "-" }}</span>
              <span class="meta__cell" v-if="row.address">地址：{{ row.address }}</span>
            </div>
            <div class="item__meta">
              <span class="meta__cell">浏览器：{{ row.browser || "-" }}</span>
              <span class="meta__cell">系统：{{ row.osInfo || "-" }}</span>
            </div>
          </div>
        </el-timeline-item>
      </el-timeline>

      <div class="footer-status" v-if="items.length">
        <el-text type="info" v-if="loading">加载中…</el-text>
        <el-text type="info" v-else-if="!hasMore">没有更多了</el-text>
      </div>
    </div>
  </el-drawer>
</template>

<script setup lang="ts">
import { computed, reactive, ref, watch, nextTick } from "vue";
import { getLogByAuthPageApi } from "@/api/modules/system/logByAuth";
import type { LogByAuth, ResPage } from "@/api/interface";
import dayjs from "dayjs";

defineOptions({
  name: "SystemUserLoginLog"
});

/** 用户登陆记录 */
interface LoginLogProps {
  account: string;
  userName?: string;
  width?: string | number;
}

/** 父组件传过来的参数 */
const parameter = ref<LoginLogProps>({
  account: "",
  width: 420
});
const drawerVisible = ref(false);

/**
 * 接收父组件参数
 *
 * @param params 父组件传过来的参数
 * @returns void
 */
const acceptParams = (params: LoginLogProps) => {
  parameter.value = params;
  drawerVisible.value = true;
};

// 抽屉宽度，默认 420px
const drawerWidth = computed(() => parameter.value.width ?? 420);

// 列表与分页状态
type Row = LogByAuth.Result;
const items = ref<Row[]>([]);
const page = reactive({
  pageIndex: 1,
  pageSize: 20,
  totalPages: 1,
  hasNextPages: false
});
const loading = ref(false);
const isFirstLoading = ref(false);

// 是否还有更多数据
const hasMore = computed(() => page.hasNextPages || page.pageIndex < page.totalPages);

// 滚动容器引用与禁用加载判断
const scrollEl = ref<HTMLDivElement | null>(null);
const disableLoadMore = computed(() => !drawerVisible.value || loading.value || !parameter.value.account || !hasMore.value);

// 时间格式化
function formatTime(val?: string) {
  if (!val) return "";
  return dayjs(val).format("YYYY-MM-DD HH:mm:ss");
}

// 重置列表
function resetList() {
  items.value = [];
  page.pageIndex = 1;
  page.totalPages = 1;
  page.hasNextPages = false;
}

// 获取数据
async function fetchList(isFirst = false) {
  if (!parameter.value.account) return;
  if (loading.value) return;
  loading.value = true;
  if (isFirst) isFirstLoading.value = true;
  try {
    const params: LogByAuth.PageParams = {
      account: parameter.value.account,
      pageIndex: page.pageIndex,
      pageSize: page.pageSize,
      isAscending: false,
      orderField: "createTime"
    };
    const { data } = await getLogByAuthPageApi(params);
    const pageData = data as unknown as ResPage<Row>;
    items.value.push(...(pageData.items ?? []));
    page.totalPages = pageData.totalPages ?? 1;
    page.hasNextPages = pageData.hasNextPages ?? false;
  } finally {
    loading.value = false;
    if (isFirst) isFirstLoading.value = false;
  }
}

// 下一页
function loadMore() {
  if (!hasMore.value || loading.value) return;
  page.pageIndex += 1;
  fetchList(false);
}

// 滚动触底
function onScroll(e: Event) {
  if (disableLoadMore.value) return;
  const el = e.target as HTMLDivElement;
  const distance = 80;
  if (el.scrollTop + el.clientHeight >= el.scrollHeight - distance) {
    loadMore();
  }
}

// 抽屉开关/账号变化时加载
watch(
  () => [drawerVisible.value, parameter.value.account] as const,
  async ([show, acc], [prevShow, prevAcc]) => {
    if (show && acc && (acc !== prevAcc || !prevShow)) {
      resetList();
      await nextTick();
      fetchList(true);
      if (scrollEl.value) scrollEl.value.scrollTop = 0;
    }
    if (!show && prevShow) {
      resetList();
    }
  },
  { immediate: false }
);

// 暴露给父组件的属性和方法
defineExpose({
  acceptParams
});
</script>

<style lang="scss" scoped>
.ml8 {
  margin-left: 8px;
}
.mt12 {
  margin-top: 12px;
}
.drawer-body {
  height: 100%;
  padding: 12px 0;
  overflow: auto; /* 使滚动监听生效 */
}
.item {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.item__header {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 2px;
}
.item__user {
  font-weight: 600;
}
.item__meta {
  font-size: 12px;
  color: var(--el-text-color-secondary);
}
.meta__cell {
  margin-right: 16px;
}
.footer-status {
  display: flex;
  justify-content: center;
  padding: 8px 0;
}
</style>
